#include "library.h"
#include "log.h"
#include "config.h"
#include "env.h"

namespace qtch {

static Logger::ptr logger = QTCH_LOG_NAME("system");

typedef Module* (*create_module)();
typedef void (*destroy_module)(Module*);


class ModuleCloser{
public:
    ModuleCloser(void* handle, destroy_module destroy){
        m_handle = handle;
        m_destroy = destroy;
    }

    void operator()(Module* m){
        std::string name = m->getName();
        std::string version = m->getVersion();
        std::string desc = m->getDesc();
        std::string fileName = m->getFileName();
        m_destroy(m);
        int rt = dlclose(m_handle);
        if(rt){
            QTCH_LOG_ERROR(logger) << "dlclose handle faile handle=" << m_handle
                << " name=" << name
                << " version=" << version
                << " file=" << fileName
                << " desc=" << desc
                << " error=" << dlerror();
        }else{
            QTCH_LOG_INFO(logger) << "destroy module=" << name 
                << " version=" << version
                << " file=" << fileName
                << " desc=" << desc
                << " success";
        }
    }

private:
    void * m_handle;
    destroy_module m_destroy;
};


Module::ptr Library::LoadModule(const std::string& path){
    void * handle = dlopen(path.c_str(),RTLD_NOW);
    if(!handle){
        QTCH_LOG_ERROR(logger) << "can't load library path=" << path << " errno=" << errno 
                << " errstr=" << strerror(errno) << " dlerror=" << dlerror();
        return nullptr;
    }
    create_module create = (create_module)dlsym(handle,"CreateModule");
    if(!create){
        QTCH_LOG_ERROR(logger)<< "can't load symbol CreateModule from path=" << path
            << " errno=" << errno << " errstr=" << strerror(errno);
        dlclose(handle);
        return nullptr; 
    }

    destroy_module destory = (destroy_module)dlsym(handle,"DestoryModule");
    if(!destory){
        QTCH_LOG_ERROR(logger)<< "can't load symbol DestoryModule from path=" << path
            << " errno=" << errno << " errstr=" << strerror(errno);
        dlclose(handle);
        return nullptr; 
    }

    Module::ptr module_ptr(create(),ModuleCloser(handle,destory));
    module_ptr->setFileName(path);
    QTCH_LOG_DEBUG(logger) << "load module name=" << module_ptr->getName()
        << " version=" << module_ptr->getVersion()
        << " desc=" << module_ptr->getDesc()
        << " file=" << module_ptr->getFileName()
        << " success";
    return module_ptr;

}

}